package de.slothsoft.commons.reflection;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import sun.misc.Launcher;
import de.slothsoft.commons.debug.Console;

public class ReflectionUtil {

	/**
	 * Find all classes of a package.
	 * 
	 * @param packageName
	 *            - the name of the package
	 * @return list of classes
	 * @throws FileNotFoundException
	 */

	public static List<Class<?>> findClasses(String packageName) throws FileNotFoundException {
		return findClasses(packageName, Launcher.class);
	}

	/**
	 * Find all classes of a package.
	 * 
	 * @param packageName
	 *            - the name of the package
	 * @param referenceClass
	 *            - the reference class
	 * @return list of classes
	 * @throws FileNotFoundException
	 */

	@SuppressWarnings("nls")
	public static List<Class<?>> findClasses(String packageName, Class<?> referenceClass) throws FileNotFoundException {

		String absolutPath = packageName;
		absolutPath = absolutPath.replace('.', '/');
		if (!absolutPath.startsWith("/")) {
			absolutPath = "/" + absolutPath;
		}

		List<Class<?>> result = new ArrayList<Class<?>>();
		// get a file for the package
		URL url = referenceClass.getResource(absolutPath);
		if (url == null) {
			throw new FileNotFoundException(url + " was not found!");
		}
		File directory = new File(url.getFile().replace("%20", " "));

		if (directory.exists()) {

			// list children
			String[] files = directory.list();
			for (String file : files) {

				// we are only interested in .class files
				if (file.endsWith(".class")) {
					// removes the .class extension
					String classname = file.substring(0, file.length() - 6);
					try {
						// Try to create an instance of the object
						Class<?> clazz = Class.forName(packageName + "." + classname);
						result.add(clazz);
					} catch (ClassNotFoundException e) {
						// should not happen, I guess
						Console.error(e);
					}
				}
			}
		}
		return result;
	}
}
